﻿using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using McHotspoot;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace McCloudCore
{
    public static class McControl
    {
        public static string split(double n, string codein, string codeout, double npt)
        {
            DateTime startTime = DateTime.Now;             
            string key = DateTime.Now.ToString("yyyyMMddHHmmssfff") + Guid.NewGuid().ToString("N"); ;
            Log.WriteInformation("WCFRole - Split Start: "+key);
            
            McHotspotI hotspoot = McHotspotFactory.create();
            string error = hotspoot.test(key+"_teste", n, codein, codeout, npt);
            if (error.Length != 0)
            {
                Log.WriteInformation("WCFRole - Split End: " + key + "(Error - "+error+")");
                return error;
            }
                        
            McQueue queue = new McQueue();                         
            double nInstancesAdded = 0; double nTasks = 0; int timeoutInSeconds = 0;
            hotspoot.optimization(n, codein, codeout, npt, out nInstancesAdded, out nTasks, out timeoutInSeconds);
            double maxPerTask = (double) Math.Truncate((decimal)(n / nTasks));
            double plusLast = (n - (nTasks * maxPerTask));                        
            for (double i = 1; i <= nTasks; i++)
            {
                double myN = 0;
                if (nTasks != i) myN = maxPerTask;
                else myN = maxPerTask + plusLast;
                Task task = new Task(key, codein, n, i, myN);
                queue.put(task, timeoutInSeconds);
                
            }
            TimeSpan durationsplit = DateTime.Now.Subtract(startTime);
            double t1 = (double)Math.Round((decimal)durationsplit.TotalMilliseconds, 0);

            Log.WriteInformation("WCFRole - Split End: " + key + "(" + nTasks + " tasks)");

            McTableEntity line = new McTableEntity();
            line.key = key;
            line.interactions = n;
            line.codein = codein;
            line.codeout = codeout;
            line.tasks = nTasks;
            line.status = 1;
            line.instancesadded = nInstancesAdded;
            line.durationsplit = t1;
            line.timeout = timeoutInSeconds;
            line.Save();
            return key;
        }
        
        public static void process()
        {
            Log.WriteInformation("WorkerRole - Process Start");

            McHotspotI hotspoot = McHotspotFactory.create();
            int TimeoutDefaultInSeconds;
            try
            {
                string TimeoutDefaultString = RoleEnvironment.GetConfigurationSettingValue("TimeoutDefaultInSeconds");
                TimeoutDefaultInSeconds = Int32.Parse(TimeoutDefaultString);
                if (TimeoutDefaultInSeconds > (2 * 60 * 60)) TimeoutDefaultInSeconds = 2 * 60 * 60;
                else if (TimeoutDefaultInSeconds < 0) TimeoutDefaultInSeconds = 30;
            }
            catch{ TimeoutDefaultInSeconds = 2 * 60 * 60; }

            while (true)
            {
                McQueue queue = new McQueue();
                Task task = null;
                if (RoleEnvironment.GetConfigurationSettingValue("WorkerRoleOn") == "true") 
                    task = queue.get(TimeoutDefaultInSeconds);
                
                if (task == null)
                {
                    System.Threading.Thread.Sleep(10000); // Wait 10 seconds                    
                    continue;                
                }
                Log.WriteInformation("Pop Task: " + task.key + " - " + task.index);   
                
                if (task.n != 0)
                {
                    McBlob blob = new McBlob();
                    string r = "";
                                        
                    if (blob.exist(task.key, task.index))
                    {
                        Log.WriteWarning("Duplicate Task: " + task.key + " - " + task.index);   
                        try{ queue.delete(); }
                        catch (Exception exception) { Log.WriteError("Delete Duplicate Task Fail: " + task.key + " - " + task.index + ": " + exception.ToString()); }
                        continue;
                    }
                             
                    try
                    {
                        Log.WriteInformation("Start Task Process: " + task.key + " - " + task.index);
                        string message = "";
                        r = hotspoot.execute(task.key, task.myN, task.index, task.code, out message);
                        Log.WriteInformation(message);
                        Log.WriteInformation("End Task Process: " + task.key + " - " + task.index);                           
                    }
                    catch (Exception exception) { Log.WriteError("Error Task Processos: " + task.key + " - " + task.index + ": " + exception.ToString()); }

                    try
                    {
                        blob.create(task.key, task.index.ToString(), r);
                        Log.WriteInformation("Save Task Process Blob: " + task.key + " - " + task.index);
                    }
                    catch (Exception exception) { Log.WriteError("Error Task Process Blob: " + task.key + " - " + task.index + ": " + exception.ToString()); }
                }

                
                try
                { 
                    queue.delete();
                    Log.WriteInformation("Delete Task: " + task.key + " - " + task.index);   
                }
                catch (Exception exception) { Log.WriteError("Error Delete Task: " + task.key + " - " + task.index + ": " + exception.ToString()); }
                    
                merge(task.key, task.index);
            }
        }

        public static void merge(string key, double index)
        {   
            McBlob blob = new McBlob();
            McTableEntity line = new McTableEntity();
            line.key = key;
            bool ok = line.Load();
            if (!ok)
            {
                Log.WriteError("Merge not found key: " + key);                   
                return;
            }
            
            double total = blob.count(key);
            if (total < line.tasks) return;
            if (line.status == 3)
            {
                Log.WriteWarning("Merge error: " + key + "(status = 3)"); 
                return;
            }
            if(line.status == 2 && index != 0) 
            {
                Log.WriteWarning("Merge error: " + key + "(duplicate)"); 
                return;
            }  
          
            Log.WriteInformation("Start Merge: " + key);   

            if(line.status != 2)
            {
                TimeSpan durationprocess = DateTime.Now.Subtract(line.Timestamp);
                double t2 = (double)Math.Round((decimal)durationprocess.TotalMilliseconds, 0);
                line.status = 2;
                line.durationprocess = t2;
                line.Update();
            }
            
            DateTime start = DateTime.Now;
            Log.WriteInformation("Start blob aggregate: " + key);
            string temp = "";
            try
            {
                temp = blob.concatenate(line.key, line.tasks);
                Log.WriteInformation("End Start blob aggregate: " + key);
            }
            catch (Exception exception1) { Log.WriteError("Error Start blob aggregate: " + key + ": " + exception1.ToString()); }
        
            
            try{
                Log.WriteInformation("Start approximation: " + key);
                McHotspotI hotspoot = McHotspotFactory.create();
                string message = "";
                string m = hotspoot.finish(line.key, line.interactions, temp, line.codein, line.codeout, out message);
                Log.WriteInformation(message);
                blob.create(key, "FINAL", m);
                Log.WriteInformation("End approximation: " + key);
            }
            catch (Exception exception2) { Log.WriteError("Error approximation: " + key + ": " + exception2.ToString()); }

            TimeSpan durationmerge = DateTime.Now.Subtract(start);
            double t3 = (double)Math.Round((decimal)durationmerge.TotalMilliseconds, 0);
            line.durationmerge = (t3);
            line.status = 3;
            line.Update();
            Log.WriteInformation("End Merge: " + key);
        }

        public static string get(string key)
        {
            McTableEntity line = new McTableEntity();
            line.key = key;
            bool ok = line.Load();
            if (!ok) return "";
            if (line.status != 3) return "";

            McBlob blob = new McBlob();
            return blob.getUri(line.key, "FINAL");
        }

        public static string check(string key)
        {
            McTableEntity line = new McTableEntity();
            line.key = key;
            bool ok = line.Load();
            if (!ok) return "invalid";
            else if (line.status == 3) return "finished";
            else if (line.status == 2) return "merging";
            else if (line.status == 1)
            {
                McBlob blob = new McBlob();
                double total = blob.count(key);
                double p = (total / line.tasks * 100);
                return "processing (" + p.ToString() + "% done)";
            }
            else return "error";
        }

        public static void onstart()
        {
            McBlob blob = new McBlob();
            blob.onStartContainer();
            Log.WriteInformation("Onstart done!");
        }
    }
}
